/*
 * MIT License
 *
 * Copyright (c) [2017] [Shobhit Puri]
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.shobhitpuri.custombuttons;

import ohos.agp.colors.RgbColor;
import ohos.agp.components.*;
import ohos.agp.components.element.ShapeElement;
import ohos.agp.components.element.StateElement;
import ohos.agp.utils.Color;
import ohos.agp.utils.TextAlignment;

import ohos.app.Context;

import ohos.global.resource.NotExistException;
import ohos.global.resource.WrongTypeException;

import ohos.multimodalinput.event.TouchEvent;

import java.io.IOException;

import static com.shobhitpuri.custombuttons.util.Constants.BUTTON_TEXT_SIZE;

/**
 * This is a customized Sign In button. Supports:
 * - app:mIsDarkTheme - get both dark and light theme using this attribute.
 * <p>
 * Created by shobhit on 2017-09-11.
 */
public class SignInButton extends DirectionalLayout {
    /**
     * Text that user wants the button to have.
     */
    private String mText;
    private boolean mIsDarkTheme;
    private Button button;
    private Image image;
    private float startY;
    private float startX;
    private boolean isEndMoving;

    /**
     * Constructor
     *
     * @param context Context
     */
    public SignInButton(Context context) {
        super(context);
    }

    /**
     * Constructor
     *
     * @param context      Context
     * @param attributeSet AttributeSet
     */
    public SignInButton(Context context, AttrSet attributeSet) {
        super(context, attributeSet);
        init(context, attributeSet, null);
    }

    /**
     * Constructor
     *
     * @param context      Context
     * @param attributeSet AttributeSet
     * @param defStyleAttr int
     */
    public SignInButton(Context context, AttrSet attributeSet, String defStyleAttr) {
        super(context, attributeSet, defStyleAttr);
    }

    /**
     * Initialize the process to get custom attributes from xml and set button params.
     *
     * @param context      Context
     * @param attributeSet AttributeSet
     * @param defStyleAttr defStyleAttr
     */
    private void init(Context context, AttrSet attributeSet, String defStyleAttr) {
        parseAttributes(context, attributeSet, defStyleAttr);
        initImage();
        setButtonParams();
        initRootView();
    }

    private void initRootView() {
        setLayoutConfig(new LayoutConfig(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_CONTENT));
        setOrientation(DirectionalLayout.HORIZONTAL);
        addComponent(image);
        addComponent(button);
        setAlignment(TextAlignment.CENTER);
        setPadding(4, 5, 10, 5);
        setMarginRight(12);
        setClickable(true);
        setBackground();
        setTouchEventListener(new TouchEventListener() {
            @Override
            public boolean onTouchEvent(Component component, TouchEvent touchEvent) {

                if (touchEvent.getAction() == TouchEvent.PRIMARY_POINT_DOWN) {
                    startY = touchEvent.getPointerPosition(touchEvent.getIndex()).getY();
                    startX = touchEvent.getPointerPosition(touchEvent.getIndex()).getX();
                    isEndMoving = false;
                    image.setPixelMap(ResourceTable.Media_icon_pressed);
                } else if (touchEvent.getAction() == TouchEvent.POINT_MOVE) {
                    if (!isEndMoving) {
                        if (isMoveOver(touchEvent)) {
                            isEndMoving = true;
                            image.setPixelMap(ResourceTable.Media_ic_icon);
                        } else {
                            image.setPixelMap(ResourceTable.Media_icon_pressed);
                        }
                    }
                } else if (touchEvent.getAction() == TouchEvent.PRIMARY_POINT_UP) {
                    isEndMoving = true;
                    image.setPixelMap(ResourceTable.Media_ic_icon);
                } else {
                }
                return true;
            }
        });
    }

    private boolean isMoveOver(TouchEvent ev) {
        double currentY = ev.getPointerPosition(ev.getIndex()).getY();
        double scrollY = currentY - startY;
        int offsetY = (int) scrollY;

        final double currentX = ev.getPointerPosition(ev.getIndex()).getX();
        double scrollX = currentX - startX;
        int offsetX = (int) scrollX;

        if (Math.abs(offsetY) > 6 || Math.abs(offsetX) > 6) {
            return true;
        } else {
            return false;
        }
    }

    private void initImage() {
        image = new Image(getContext());
        image.setLayoutConfig(new LayoutConfig(110, 110));
        image.setScaleMode(Image.ScaleMode.STRETCH);
        image.setMarginRight(15);
        image.setPixelMap(ResourceTable.Media_ic_icon);
    }

    /**
     * Parses out the custom attributes.
     *
     * @param context      Context
     * @param attributeSet AttributeSet
     * @param defStyleAttr defStyleAttr
     */
    private void parseAttributes(Context context, AttrSet attributeSet, String defStyleAttr) {
        if (attributeSet == null) {
            return;
        }
        // Get the attribute to check if user wants dark theme.
        mIsDarkTheme = attributeSet.getAttr("isDarkTheme").isPresent() ? attributeSet.getAttr("isDarkTheme").get().getBoolValue() : false;
        // Get text which user wants to set the button.
        mText = attributeSet.getAttr("text").isPresent() ? attributeSet.getAttr("text").get().getStringValue() : getDefaultString();
    }

    private String getDefaultString() {
        String defaultString = null;
        try {
            defaultString = getContext().getResourceManager().getElement(ResourceTable.String_sign_in).getString();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (NotExistException e) {
            e.printStackTrace();
        } catch (WrongTypeException e) {
            e.printStackTrace();
        }
        return defaultString;
    }

    private void setButtonParams() {
        // We need not have only upper case character.
        button = new Button(getContext());
        button.setLayoutConfig(new LayoutConfig(LayoutConfig.MATCH_CONTENT, LayoutConfig.MATCH_PARENT));
        button.setTextAlignment(TextAlignment.VERTICAL_CENTER);
        button.setMarginLeft(8);
        button.setMarginRight(8);
        button.setClickable(false);
        // Set button text
        setButtonText();
        // Set button text size
        setButtonTextSize();
        // Set button text color
        setButtonTextColor();
        // Set background of button
    }

    /**
     * Set the text size to standard as mentioned in guidelines.
     */
    private void setButtonTextSize() {
        button.setTextSize(BUTTON_TEXT_SIZE, Text.TextSizeType.VP);
    }

    /**
     * Check the theme and set background based on theme which is a selector.
     * The selector handles the background color when button is clicked.
     */
    private void setBackground() {
        // 创建正常状态下元素
        ShapeElement normalElement = new ShapeElement();
        if (mIsDarkTheme) {
            normalElement.setShape(ShapeElement.RECTANGLE);
            normalElement.setRgbColor(RgbColor.fromArgbInt(Color.getIntColor("#4285F4")));
            normalElement.setCornerRadius(5);
        } else {
            normalElement.setShape(ShapeElement.RECTANGLE);
            normalElement.setRgbColor(RgbColor.fromArgbInt(Color.getIntColor("#FFFFFF")));
            normalElement.setCornerRadius(5);
        }
        // 创建按下状态下元素
        ShapeElement pressedShapeElement = new ShapeElement();
        if (mIsDarkTheme) {
            pressedShapeElement.setShape(ShapeElement.RECTANGLE);
            pressedShapeElement.setRgbColor(RgbColor.fromArgbInt(Color.getIntColor("#3367D5")));
            pressedShapeElement.setCornerRadius(5);
        } else {
            pressedShapeElement.setShape(ShapeElement.RECTANGLE);
            pressedShapeElement.setRgbColor(RgbColor.fromArgbInt(Color.getIntColor("#EEEEEE")));
            pressedShapeElement.setCornerRadius(5);
        }

        StateElement stateElement = new StateElement();

        stateElement.addState(new int[]{ComponentState.COMPONENT_STATE_PRESSED}, pressedShapeElement);
        stateElement.addState(new int[]{ComponentState.COMPONENT_STATE_SELECTED}, pressedShapeElement);
        stateElement.addState(new int[]{ComponentState.COMPONENT_STATE_DISABLED}, pressedShapeElement);
        stateElement.addState(new int[]{ComponentState.COMPONENT_STATE_CHECKED}, pressedShapeElement);
        stateElement.addState(new int[]{ComponentState.COMPONENT_STATE_EMPTY}, normalElement);
        setBackground(stateElement);
    }

    /**
     * Check the theme and set text color based on theme.
     */
    private void setButtonTextColor() {
        Color textColor = mIsDarkTheme ? Color.WHITE : Color.BLACK;
        button.setTextColor(textColor);
    }

    /**
     * If user has set text, that takes priority else use default button text.
     */
    private void setButtonText() {
        if (mText == null || mText.isEmpty()) {
            mText = getDefaultString();
        }
        button.setText(mText);
    }

}
